package org.sorz.lab.smallcloudemoji.tasks;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import com.google.common.io.CountingInputStream;
import org.sorz.lab.smallcloudemoji.R;
import org.sorz.lab.smallcloudemoji.db.Category;
import org.sorz.lab.smallcloudemoji.db.DaoSession;
import org.sorz.lab.smallcloudemoji.db.DatabaseHelper;
import org.sorz.lab.smallcloudemoji.db.Entry;
import org.sorz.lab.smallcloudemoji.db.Repository;
import org.sorz.lab.smallcloudemoji.db.Source;
import org.sorz.lab.smallcloudemoji.db.SourceDao;
import org.sorz.lab.smallcloudemoji.exceptions.LoadingCancelException;
import org.sorz.lab.smallcloudemoji.parsers.RepositoryJsonLoader;
import org.sorz.lab.smallcloudemoji.parsers.RepositoryLoader;
import org.sorz.lab.smallcloudemoji.parsers.RepositoryLoaderEventListener;
import org.sorz.lab.smallcloudemoji.parsers.RepositoryXmlLoader;
import org.xmlpull.v1.XmlPullParserException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
/**
* Download and save a XML file.
*/
public class DownloadAsyncTask extends AsyncTask<Repository, Integer, Integer> {
private final Context context;
private final DaoSession daoSession;
protected static final int RESULT_CANCELLED = -1;
protected static final int RESULT_SUCCESS = 0;
private static final int RESULT_ERROR_MALFORMED_URL = 1;
private static final int RESULT_ERROR_IO = 2;
private static final int RESULT_ERROR_XML_PARSER = 3;
private static final int RESULT_ERROR_UNKNOWN = 4;
private static final int RESULT_ERROR_NOT_FOUND = 5;
private static final int RESULT_ERROR_OTHER_HTTP = 6;
private static final int RESULT_ERROR_UNSUPPORTED_FORMAT = 7;
public DownloadAsyncTask(Context context) {
super();
this.context = context;
daoSession = DatabaseHelper.getInstance(context, true).getDaoSession();
}
@Override
protected Integer doInBackground(Repository... params) {
InputStream inputStream = null;
HttpURLConnection connection = null;
Repository repository = params[0];
try {
URL url = new URL(repository.getUrl());
for (int i = 0; i < 10; ++i) { // Limit redirection (between HTTP and HTTPS) < 10 times.
connection = (HttpURLConnection) url.openConnection();
int statusCode = connection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_OK) {
break;
} else if (statusCode == HttpURLConnection.HTTP_MOVED_TEMP ||
statusCode == HttpURLConnection.HTTP_MOVED_PERM) {
url = connection.getURL();
} else if (statusCode == HttpURLConnection.HTTP_NOT_FOUND) {
return RESULT_ERROR_NOT_FOUND;
} else {
return RESULT_ERROR_OTHER_HTTP;
}
}
if (connection == null)
return RESULT_ERROR_OTHER_HTTP;
final int fileLength = connection.getContentLength();
final CountingInputStream counting = new CountingInputStream(connection.getInputStream());
inputStream = counting;
RepositoryLoader repositoryLoader;
String contentType = connection.getContentType();
String filename = connection.getURL().getFile().toLowerCase();
if (contentType.startsWith("text/xml") || filename.endsWith(".xml"))
repositoryLoader = new RepositoryXmlLoader(daoSession);
else if (contentType.startsWith("application/json") || filename.endsWith(".json"))
repositoryLoader = new RepositoryJsonLoader(daoSession);
else
return RESULT_ERROR_UNSUPPORTED_FORMAT;
repositoryLoader.setLoaderEventListener(new RepositoryLoaderEventListener() {
private long lastUpdateProcess;
public boolean onLoadingCategory(Category category) {
return isCancelled();
}
@Override
public boolean onEntryLoaded(Entry entry) {
if (System.currentTimeMillis() - lastUpdateProcess >= 100) {
int process = (int) counting.getCount() * 100 / fileLength;
publishProgress(process);
lastUpdateProcess = System.currentTimeMillis();
}
return isCancelled();
}
});
repositoryLoader.loadToDatabase(repository,
new BufferedReader(new InputStreamReader(inputStream)));
// Update source install state.
SourceDao sourceDao = daoSession.getSourceDao();
List<Source> sources = sourceDao.queryBuilder()
.where(SourceDao.Properties.CodeUrl.eq(repository.getUrl()),
SourceDao.Properties.Installed.eq(false))
.list();
if (!sources.isEmpty()) {
for (Source source : sources)
source.setInstalled(true);
sourceDao.updateInTx(sources);
}
} catch (LoadingCancelException e) {
return RESULT_CANCELLED;
} catch (MalformedURLException e) {
return RESULT_ERROR_MALFORMED_URL;
} catch (IOException e) {
return RESULT_ERROR_IO;
} catch (XmlPullParserException e) {
return RESULT_ERROR_XML_PARSER;
} catch (Exception e) {
e.printStackTrace();
return RESULT_ERROR_UNKNOWN;
} finally {
DatabaseHelper.getInstance(context).close();
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
// Ignore it
}
if (connection != null)
connection.disconnect();
}
return RESULT_SUCCESS;
}
@Override
protected void onCancelled(Integer result) {
super.onCancelled(result);
if (result != DownloadAsyncTask.RESULT_CANCELLED)
onPostExecute(result);
}
@Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
if (result == RESULT_SUCCESS) {
Toast.makeText(context, R.string.download_success, Toast.LENGTH_SHORT).show();
return;
}
String message = context.getString(R.string.download_fail);
if (result == RESULT_ERROR_MALFORMED_URL)
message = String.format(message, context.getString(R.string.download_malformed_url));
else if (result == RESULT_ERROR_IO)
message = String.format(message, context.getString(R.string.download_io_exception));
else if (result == RESULT_ERROR_NOT_FOUND)
message = String.format(message, context.getString(R.string.download_no_found));
else if (result == RESULT_ERROR_XML_PARSER)
message = String.format(message, context.getString(R.string.download_file_parser_error));
else if (result == RESULT_ERROR_OTHER_HTTP)
message = String.format(message, context.getString(R.string.download_http_error));
else if (result == RESULT_ERROR_UNSUPPORTED_FORMAT)
message = String.format(message, context.getString(R.string.download_unsupported));
else
message = String.format(message, context.getString(R.string.download_unknown_error));
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}